home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
081-090
/
amok89
/
amigaguide
/
nodehost.mod
< prev
next >
Wrap
Text File
|
1993-11-04
|
10KB
|
345 lines
MODULE NodeHost;
(*---------------------------------------------------------------------------
** Written by David N. Junod
**
** Example of a Dynamic Node Host. This example is useful for determining
** what nodes an AmigaGuide database is calling when it brings up the
** "Can't locate node" requester.
**
** I use it when I'm writing help files for AppShell applications...
**
** This is a translation of the NodeHost.c example supplied with the
** AmigaGuide v1.24 package.
**---------------------------------------------------------------------------
** Oberon: Amiga-Oberon v3.00, F. Siebert / A+L AG
**---------------------------------------------------------------------------
** 14-Apr-93 [lars] created
** 14-Apr-93 [lars] actual
**---------------------------------------------------------------------------
*)
IMPORT ag:AmigaGuide, Dos, e:Exec, gr:Graphics, i:Intuition, sys:SYSTEM,
Utility,
(* $IF Debug *) Debug, (* $END *)
io, NoGuru, Requests;
(*-------------------------------------------------------------------------*)
CONST
TempNode = "This AmigaGuideHost is example, that can also\nbe used as a debugging tool.\n";
Link = "Link: ";
Topaz8 = gr.TextAttr (sys.ADR("topaz.font"), 8, SHORTSET{}, SHORTSET{} );
Topaz8B = gr.TextAttr (sys.ADR("topaz.font"), 8, SHORTSET{gr.bold}, SHORTSET{} );
(*-------------------------------------------------------------------------*)
PROCEDURE ^ dispatchAmigaGuideHost ( h : Utility.HookPtr;
db : e.APTR;
msg : e.APTR
) : LONGINT;
PROCEDURE Main ();
VAR
hook : Utility.Hook;
hh : ag.AmigaGuideHostPtr;
BEGIN
(* Initialize the hook *)
Utility.InitHook (sys.ADR(hook), dispatchAmigaGuideHost);
(* Add the AmigaGuideHost to the system *)
hh := ag.AddAmigaGuideHost (hook, "ExampleHost", NIL);
IF hh # NIL THEN
io.WriteString ("Added AmigaGuideHost $");
io.WriteHex (sys.VAL(sys.ADDRESS, hh), 1); io.WriteLn;
(* Wait until we're told to quit *)
sys.SETREG(0, e.Wait (LONGSET{Dos.ctrlC}));
io.WriteString ("Remove AmigaGuideHost $");
io.WriteHex (sys.VAL(sys.ADDRESS, hh), 1); io.WriteLn;
(* Try removing the host *)
WHILE ag.RemoveAmigaGuideHost (hh, NIL) > 0 DO
(* Wait a while *)
io.Write (".");
Dos.Delay (250);
END;
io.WriteLn;
ELSE
io.WriteString ("Couldn't add AmigaGuideHost\n");
END;
END Main;
(*-------------------------------------------------------------------------*)
(***** Common tag manipulation routines ************************************)
(* $OvflChk- for pointer arithmetics *)
PROCEDURE nextTagItem (VAR tp : Utility.TagItemPtr) : Utility.TagItemPtr;
TYPE
TIA = ARRAY 2 OF Utility.TagItem;
TIP = UNTRACED POINTER TO TIA;
VAR
nextti : TIP;
BEGIN
(* 'tp' already holds "next" item in list *)
nextti := sys.VAL (TIP, tp);
(* walk all TAG_MORE and TAG_IGNORE chaining *)
WHILE nextti # NIL DO
CASE sys.VAL(LONGINT, nextti[0].tag) OF
| Utility.more: nextti := nextti[0].data;
| Utility.skip:
(* nextti := sys.ADR (nextti[1+nextti[0].data]); *)
nextti := sys.VAL ( TIP,
sys.VAL(LONGINT, nextti)
+ (1+sys.VAL(LONGINT, nextti[0].data))
* SIZE(Utility.TagItem)
);
| Utility.ignore: nextti := sys.ADR (nextti[1]);
| Utility.done: tp := NIL; RETURN tp;
ELSE (* a normal tag item *)
tp := sys.ADR (nextti[1]);
RETURN sys.VAL(Utility.TagItemPtr, nextti);
END;
END;
tp := NIL;
RETURN tp;
END nextTagItem;
(* $OvflChk= *)
(*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*)
PROCEDURE findTagItem ( tag : Utility.Tag;
ti : Utility.TagItemPtr
) : Utility.TagItemPtr;
VAR
tistate : Utility.TagItemPtr;
BEGIN
tistate := ti;
REPEAT
ti := nextTagItem (tistate);
UNTIL (ti = NIL) OR (ti.tag = tag);
RETURN ti;
END findTagItem;
(*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*)
PROCEDURE getTagData ( tag : Utility.Tag;
deflt : LONGINT;
ti : Utility.TagItemPtr
) : LONGINT;
BEGIN
ti := findTagItem ( tag, ti );
IF ti # NIL THEN RETURN ti.data; END;
RETURN deflt;
END getTagData;
(*-------------------------------------------------------------------------*)
PROCEDURE Display (onm : ag.OpNodeIOPtr);
(* We really need the screen, rectangle, and pen spec. *)
TYPE
PenA = ARRAY i.shadowPen+1 OF SHORTINT;
PenP = UNTRACED POINTER TO PenA;
VAR
attrs : Utility.TagItemPtr;
it1, it2 : i.IntuiText;
rect : gr.RectanglePtr;
nw : i.NewWindow;
scr : i.ScreenPtr;
msg : i.IntuiMessagePtr;
win : i.WindowPtr;
pens : PenP;
going : BOOLEAN;
width : LONGINT;
w, h, dif : INTEGER;
BEGIN
attrs := onm.attrs;
rect := NIL;
scr := NIL;
pens := NIL;
going := TRUE;
width := 0;
w := 640;
h := 200;
(* Get attributes, could be NIL *)
IF attrs # NIL THEN
scr := sys.VAL (i.ScreenPtr, getTagData (ag.screen, NIL, attrs));
pens := sys.VAL(PenP, getTagData (ag.pens, NIL, attrs));
rect := sys.VAL (gr.RectanglePtr, getTagData (ag.rectangle, NIL, attrs));
END;
(* Prepare the IntuiText *)
IF pens # NIL THEN it2.frontPen := pens[i.shadowPen];
ELSE it2.frontPen := 1;
END;
it1.frontPen := it2.frontPen;
it1.drawMode := gr.jam1;
it2.drawMode := gr.jam1;
it1.iTextFont := sys.ADR(Topaz8);
it2.iTextFont := sys.ADR(Topaz8B);
it1.iText := sys.ADR(Link);
it2.iText := onm.node;
(* Get the width of the first string *)
width := i.IntuiTextLength (it1);
it2.leftEdge := SHORT(width);
(* Add in the length of the node name *)
INC (width, i.IntuiTextLength (it2));
(* Link the text *)
it1.nextText := sys.ADR(it2);
(* Prepare the window *)
nw.idcmpFlags := LONGSET{i.vanillaKey, i.mouseButtons};
nw.flags := LONGSET{i.borderless, i.noCareRefresh, i.activate} + i.smartRefresh;
nw.width := SHORT(8 + width + 8);
nw.height := 16;
nw.screen := scr;
IF scr # NIL THEN nw.type := i.customScreen;
ELSE nw.type := {i.wbenchScreen};
END;
(* Cache the screen size *)
IF scr # NIL THEN
w := scr.width;
h := scr.height;
END;
(* See if we have a open help window *)
IF rect # NIL THEN
(* Center the window within the help window *)
nw.leftEdge := rect.minX + ((rect.maxX - nw.width) DIV 2);
nw.topEdge := rect.minY + ((rect.maxY - nw.height) DIV 2);
(* No help window, so go off the screen *)
ELSIF scr # NIL THEN
(* Center the window horizontally under the mouse and place it
* vertically over the mouse position. *)
nw.leftEdge := scr.mouseX - (nw.width DIV 2);
nw.topEdge := scr.mouseY - (nw.height - 2);
(* Make sure the window can open *)
IF nw.leftEdge < 0 THEN nw.leftEdge := 0; END;
IF nw.topEdge < 0 THEN nw.topEdge := 0; END;
END;
(* Make sure window is on-screen *)
dif := (nw.leftEdge + nw.width) - w;
IF dif > 0 THEN DEC (nw.leftEdge, dif); END;
dif := (nw.topEdge + nw.height) - h;
IF dif > 0 THEN DEC (nw.topEdge, dif); END;
(* Open the temporary window *)
win := i.OpenWindow (nw);
IF win # NIL THEN
(* Clear the window background *)
IF pens # NIL THEN gr.SetAPen (win.rPort, pens[i.shadowPen]);
ELSE gr.SetAPen (win.rPort, 1);
END;
gr.RectFill (win.rPort, 0, 0, (win.width - 1), (win.height - 1));
IF pens # NIL THEN gr.SetAPen (win.rPort, pens[i.shinePen]);
ELSE gr.SetAPen (win.rPort, 2);
END;
gr.RectFill (win.rPort, 1, 1, (win.width - 2), (win.height - 2));
(* Print the text *)
i.PrintIText (win.rPort, it1, 8, 4);
(* Keep on going til the going gets tough *)
WHILE going DO
(* Wait around for something eventful *)
sys.SETREG(0, e.Wait (LONGSET{win.userPort.sigBit}));
(* Pull each message and handle it *)
LOOP
msg := e.GetMsg (win.userPort);
IF msg # NIL THEN EXIT; END;
IF i.mouseButtons IN msg.class THEN (* Stop if we were touched *)
IF msg.code = i.selectDown THEN going := FALSE; END;
ELSIF i.vanillaKey IN msg.class THEN (* Stop on significant keypress *)
IF (msg.code = 27) OR (msg.code = 13) THEN going := FALSE; END;
END;
e.ReplyMsg (msg);
END;
END;
(* Close the window *)
i.CloseWindow (win);
END;
END Display;
(*-------------------------------------------------------------------------*)
PROCEDURE * dispatchAmigaGuideHost ( h : Utility.HookPtr;
db : e.APTR (* e.STRPTR *);
msg : e.APTR (* ag.Msg *)
) : LONGINT;
(* This is your AmigaGuideHost dispatch hook. It will never run on your
* own process. *)
VAR
onm : ag.OpNodeIOPtr;
retval : LONGINT;
ofh : ag.OpFindHostPtr;
BEGIN
onm := sys.VAL (ag.OpNodeIOPtr, msg);
retval := e.false;
CASE onm.method.ID OF
| ag.findNode : (* Does this node belong to you? *)
ofh := sys.VAL (ag.OpFindHostPtr, msg);
(* See if they want to find our table of contents *)
IF Utility.Stricmp (ofh.node^, "main") = 0 THEN
(* Return TRUE to indicate that it's your node, else return FALSE. *)
retval := e.true;
ELSE
(* Display the name of the node *)
Display (onm);
(* Return TRUE to indicate that it's your node, else return FALSE. *)
retval := e.false;
END;
| ag.openNode : (* Open a node. *)
(* See if they want to display our table of contents *)
IF Utility.Stricmp (onm.node^, "main") = 0 THEN
(* Provide the contents of the node *)
onm.docBuffer := sys.ADR(TempNode);
onm.buffLen := SIZE (TempNode); (* should be strlen() for variant data! *)
ELSE
(* Display the name of the node *)
Display (onm);
(* Indicate that we want the node removed from our database,
* and that we handled the display of the node *)
onm.flags := onm.flags + LONGSET{ag.clean, ag.done};
END;
(* Indicate that we were able to open the node *)
retval := e.true;
| ag.closeNode : (* Close a node, that has no users. *)
(* Indicate that we were able to close the node *)
retval := e.true;
| ag.expunge : (* Free any extra memory *)
ELSE
END;
RETURN retval;
END dispatchAmigaGuideHost;
(*-------------------------------------------------------------------------*)
BEGIN
Requests.Assert (ag.base # NIL, "Can't open amigaguide.library");
Main;
END NodeHost.
(***************************************************************************)